package cn.maihe.elg.operation.supports.bank.service;

import cn.maihe.elg.operation.config.CiticBankConfig;
import cn.maihe.elg.operation.model.dto.BaseReq;
import cn.maihe.elg.operation.model.dto.BaseResp;
import cn.maihe.elg.operation.repository.entity.AcceptOrderInfoDO;
import cn.maihe.elg.operation.repository.entity.SpdBankNotice;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.SpdBankNoticeService;
import cn.maihe.elg.operation.supports.bank.BaseCiticBankTransService;
import cn.maihe.elg.operation.supports.bank.dto.*;
import cn.maihe.elg.operation.utils.ElgLogger;
import cn.maihe.elg.operation.utils.IdGenerate;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class CiticBankCardService extends BaseCiticBankTransService<BaseReq, BaseResp> {

    @Resource
    private CiticBankConfig citicBankConfig;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private SpdBankNoticeService spdBankNoticeService;
    @Resource
    private CiticBankMockService citicBankMockService;

    //测试暂时开启
    @Getter
    private boolean mockMode = true;

    @Transactional(rollbackFor = Exception.class)
    public String openNewCardAndUpdateOrder(String orderNo) {
        ElgLogger.info(log, l -> l.info("开始为订单ID {} 申请中信银行收款卡", orderNo));

        AcceptOrderInfoDO order = acceptOrderInfoService.getByAcceptOrderNo(orderNo);;
        Assert.notNull(order, "订单不存在，无法开卡！订单ID: " + orderNo);
        Assert.isNull(order.getVirtualCardNo(), "此订单已有关联的虚拟卡，请勿重复开卡。卡号: " + order.getVirtualCardNo());

        String clientId = generateCardClientId(order.getAcceptOrderNo());

        CiticCardOpenReqDTO req = new CiticCardOpenReqDTO();
        req.setUserName(citicBankConfig.getUserName());
        req.setAccountNo(citicBankConfig.getAccountNo());
        req.setSetlcardNum(citicBankConfig.getTemplateCardNo());
        req.setClientId(clientId);

        CiticCardOpenRespDTO response = sendCardOpenRequest(req);

        if (!"S2".equals(response.getStt())) {
            ElgLogger.error(log, l -> l.error("中信银行开卡失败！订单号: {}, 业务状态: {}, 原因: {}", order.getAcceptOrderNo(), response.getStt(), response.getStatusText()));
            throw new RuntimeException("中信银行开卡失败: " + response.getStatusText());
        }

        String newCardNo = response.getSetlcardNumNew();
        Assert.hasText(newCardNo, "银行开卡成功，但未返回新卡号！");

        ElgLogger.info(log, l -> l.info("订单 {} 成功申请到新卡，卡号: {}", order.getAcceptOrderNo(), newCardNo));

        order.setVirtualCardNo(newCardNo);
        order.setCardClientId(clientId);
        order.setCardStatus("ACTIVE");
        order.setGmtModified(new Date());

        int updatedRows = acceptOrderInfoService.updateById(order);
        if (updatedRows <= 0) {
            ElgLogger.error(log, l -> l.error("数据库更新失败！未能保存虚拟卡信息到订单表。订单号: {}", order.getAcceptOrderNo()));
            throw new RuntimeException("数据库更新失败，未能保存虚拟卡信息");
        }

        ElgLogger.info(log, l -> l.info("新卡信息已成功更新到订单表。订单号: {}", order.getAcceptOrderNo()));
        return newCardNo;
    }

    private CiticCardOpenRespDTO sendCardOpenRequest(CiticCardOpenReqDTO req) {
        if (mockMode) {
            ElgLogger.info(log, l -> l.info("处于Mock模式，将返回模拟的开卡响应。"));
            return citicBankMockService.generateMockCardOpenResponse(req);
        }
        String traceId = IdGenerate.genTranceId();
        try {
            String requestXml = buildRequestXml(req, CiticCardOpenReqDTO.class);
            ElgLogger.info(log, l -> l.info("{} >> 中信银行开卡请求: {}", traceId, requestXml));
            String responseXml = sendHttpRequest(requestXml);
            ElgLogger.info(log, l -> l.info("{} << 中信银行开卡响应: {}", traceId, responseXml));
            CiticCardOpenRespDTO response = parseResponseXml(responseXml, CiticCardOpenRespDTO.class);
            validateBaseResponse(response);
            return response;
        } catch (Exception e) {
            ElgLogger.error(log, l -> l.error("{} << 中信银行开卡异常: {}", traceId, e.getMessage(), e));
            throw new RuntimeException("中信银行开卡异常: " + e.getMessage(), e);
        }
    }

    private String generateCardClientId(String orderNo) {
        String clientId = "CARD_" + orderNo + "_" + System.currentTimeMillis();
        if (clientId.length() > 20) {
            return clientId.substring(clientId.length() - 20);
        }
        return clientId;
    }

    /**
     * 查询指定虚拟卡的全部交易明细，并保存到流水表
     *
     * @param virtualCardNo 要查询的虚拟卡号
     * @param startDate     查询起始日期 (YYYYMMDD)
     * @param endDate       查询结束日期 (YYYYMMDD)
     */
    public void queryAndSaveCardTransactions(String virtualCardNo, String startDate, String endDate) {
        ElgLogger.info(log, l -> l.info("开始查询虚拟卡 {} 的交易明细，日期范围: {} - {}", virtualCardNo, startDate, endDate));

        //分页查询，获取该卡在指定日期内的所有交易流水
        List<CiticCardDetailItem> allDetails = queryFullCardTransactions(virtualCardNo, startDate, endDate);

        if (allDetails.isEmpty()) {
            ElgLogger.info(log, l -> l.info("虚拟卡 {} 在指定日期内无交易明细。", virtualCardNo));
            return;
        }

        ElgLogger.info(log, l -> l.info("查询到 {} 条交易明细，开始处理并保存...", allDetails.size()));

        //遍历每一条流水，转换并保存到 t_spd_bank_notice 表
        for (CiticCardDetailItem detail : allDetails) {
            if (spdBankNoticeService.existsCoreSerNo(detail.getOrderNum())) {
                ElgLogger.info(log, l -> l.info("卡交易流水已存在，跳过。核心流水号: {}", detail.getOrderNum()));
                continue;
            }

            // 转换并保存
            SpdBankNotice notice = buildNoticeFromCardDetail(detail);
            spdBankNoticeService.saveOrUpdate(notice);
            ElgLogger.info(log, l -> l.info("新的卡交易流水已保存。核心流水号: {}", notice.getCoreSerNo()));
        }
    }

    /**
     * 分页查询并返回指定卡的所有交易明细
     */
    private List<CiticCardDetailItem> queryFullCardTransactions(String virtualCardNo, String startDate, String endDate) {
        if (mockMode) {
            ElgLogger.info(log, l -> l.info("处于Mock模式，将返回模拟的卡交易明细。"));
            CiticCardDetailRespDTO mockResponse = citicBankMockService.generateMockCardDetailResponse(virtualCardNo);
            return mockResponse.getUserDataList() != null ? mockResponse.getUserDataList() : new ArrayList<>();
        }
        List<CiticCardDetailItem> allDetails = new ArrayList<>();
        int startRecord = 1;
        final int pageSize = 20;

        while (true) {
            CiticCardDetailReqDTO req = new CiticCardDetailReqDTO();
            req.setUserName(citicBankConfig.getUserName());
            req.setAccountNo(citicBankConfig.getAccountNo());
            req.setSetlcardNum(virtualCardNo);
            req.setStartDate(startDate);
            req.setEndDate(endDate);
            req.setStartRecord(String.valueOf(startRecord));
            req.setPageNumber(String.valueOf(pageSize));

            CiticCardDetailRespDTO response;
            try {
                String requestXml = buildRequestXml(req, CiticCardDetailReqDTO.class);
                String responseXml = sendHttpRequest(requestXml);
                response = parseResponseXml(responseXml, CiticCardDetailRespDTO.class);
                validateBaseResponse(response);
            } catch (Exception e) {
                ElgLogger.error(log, l -> l.error("查询卡交易明细时发生异常", e));
                break;
            }

            if (response.getUserDataList() == null || response.getUserDataList().isEmpty()) {
                break;
            }

            allDetails.addAll(response.getUserDataList());

            if (allDetails.size() >= response.getTotalRecords()) {
                break;
            }
            startRecord += response.getReturnRecords();
        }
        return allDetails;
    }

    /**
     * 将卡交易明细 (CiticCardDetailItem) 转换为数据库实体 (SpdBankNotice)
     */
    private SpdBankNotice buildNoticeFromCardDetail(CiticCardDetailItem detail) {
        SpdBankNotice notice = new SpdBankNotice();
        notice.setId(IdGenerate.getId());

        // 交易总流水号
        notice.setCoreSerNo(detail.getOrderNum());
        notice.setNoticeSerNo(detail.getOrderNum());
        notice.setDepSerNo(detail.getOrderNum());

        // 标识为中信银行卡流水
        notice.setNoticeType("CITIC_CARD");
        notice.setParentAcctNo(detail.getRelAcc());
        notice.setParentAcctName(detail.getCardholderNm());

        //交易时间
        notice.setNoticeDate(detail.getTranDate());
        notice.setCoreTransDate(detail.getTranDate());
        notice.setTransDate(detail.getTranDate());
        // 明细接口未返回具体时间
        notice.setNoticeTime(null);
        notice.setCoreTransTime(null);
        notice.setTransTime(null);
        //交易金额
        notice.setTransAmt(detail.getTranAmt() != null ? detail.getTranAmt().toPlainString() : "0.00");
        // 对方账户信息
        notice.setAcctNo(detail.getOppositeAccNo());
        notice.setAcctName(detail.getMerchNm());
        notice.setAttach(detail.getHostTranDesc());

        // 把虚拟卡号存在子账户字段
        notice.setSubAccount(detail.getSetlcardNum());
        // 使用 remark 存储额外信息
        notice.setRemark1("借贷标识:" + detail.getSetlCardDbCrFlag());
        notice.setRemark2("交易名称:" + detail.getTranName());

        notice.setGmtCreate(new Date());
        notice.setGmtModified(new Date());
        notice.setGmtCreate(new Date());
        notice.setGmtModified(new Date());
        notice.setZoneCode("");
        notice.setSecuNo("");
        notice.setSecuName("");
        notice.setMerchNo("");
        notice.setMerchName("");
        notice.setAcctBankNo("");
        notice.setBusiType("");
        return notice;
    }
}